package com.koelo.kiss.re.interpreter.java;

import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;

import com.koelo.kiss.re.interpreter.AbstractInterpreter;
import com.koelo.kiss.re.interpreter.InterpreterException;
import com.koelo.kiss.re.interpreter.java.hotswap.ClassReloader;
import com.koelo.kiss.re.parser.IParser;
import com.koelo.kiss.re.util.Context;
import com.koelo.kiss.re.util.IContext;
import com.koelo.kiss.re.util.IMessage;
import com.koelo.kiss.re.util.IRule;
import com.koelo.kiss.re.util.ISession;

public class JavaInterpreter 
	extends AbstractInterpreter {

	private static Logger LOGGER = Logger.getLogger(JavaInterpreter.class);
	private static final String NAME = "java";
	private static final String EXTENTION = "class";
	private Map<String, IRule> resources;

	public JavaInterpreter(Context context, IParser parser) {
		
		super(context, parser);
		this.resources = new HashMap<String, IRule>();
	}

	public JavaInterpreter(IParser parser) {
		
		super(new Context(), parser);
	}

	@Override
	public String getName() {
		
		return NAME;
	}

	@Override
	public String getExtension() {
		
		return EXTENTION;
	}

	@SuppressWarnings("unchecked")
	@Override
	public IRule getResource(String name) 
		throws InterpreterException {

		try {
			IRule rule = null;
			LOGGER.info("Loading rule object " + name + ". wait.");
			if (isHotSwapMode()) {
				Class<IRule> clazz = (Class<IRule>) Class.forName(name);
				rule = new HotRule(name, clazz.newInstance(), getHotSwapPath());
			} else {
				rule = this.resources.get(name);
				if (rule == null) {
					Class<IRule> clazz = (Class<IRule>) Class.forName(name);
					rule = clazz.newInstance();
					this.resources.put(name, rule);
				}
			}
			LOGGER.info("Loading rule object " + name + ". done.");
			return rule;
		} catch (ClassNotFoundException ex) {
			throw new InterpreterException(ex);
		} catch (IllegalAccessException ex) {
			throw new InterpreterException(ex);
		} catch (InstantiationException ex) {
			throw new InterpreterException(ex);
		}
	}
}

class HotRule 
	implements IRule {

	private static Logger LOGGER = Logger.getLogger(HotRule.class);

	private final String name;
	private IRule rule;
	private String[] hotswappath;
	
	public HotRule(String name, IRule rule, String[] hotswappath) {
	
		this.name = name;
		this.rule = rule;
		this.hotswappath = hotswappath;
	}
	
	@Override
	public boolean eval(IContext context, ISession session, IMessage message) 
		throws InterpreterException {
	
		try {
			ClassReloader reloader = new ClassReloader(this.rule.getClass().getClassLoader(), this.hotswappath);
			Class<?> clazz = reloader.loadClass(this.name, true);
			this.rule = (IRule) clazz.newInstance();
			LOGGER.debug("Evaluating rule object " + this.name + ". wait.");
			boolean result = this.rule.eval(context, session, message);
			LOGGER.debug("Evaluating rule object " + this.name + ". done.");
			return result;
		} catch (ClassNotFoundException ex) {
			throw new InterpreterException(ex);
		} catch (IllegalAccessException ex) {
			throw new InterpreterException(ex);
		} catch (InstantiationException ex) {
			throw new InterpreterException(ex);
		}
	}
}
